import 'package:latlong/latlong.dart';
import 'dart:math' as Math;
///@className gsp_converter_util
///@author liaoyu
///@version 1.0.0
///@description gps坐标转换
///坐标转换工具类
///WGS84: Google Earth采用，Google Map中国范围外使用
///GCJ02: 火星坐标系，中国国家测绘局制定的坐标系统，由WGS84机密后的坐标。Google Map中国和搜搜地图使用，高德
///BD09:百度坐标，GCJ02机密后的坐标系
///搜狗坐标系，图吧坐标等，估计也是在GCJ02基础上加密而成的
///@createTime 2021/1/13 17:19

class GpsConverterUtil{

  static final double _pi = 3.1415926535897932384626;
  static final double _a = 6378245.0;
  static final double _ee = 0.00669342162296594323;

  /**
   * 84 to 火星坐标系 (GCJ-02) World Geodetic System ==> Mars Geodetic System
   * @param lat
   * @param lon
   */
   static LatLng gps84_To_Gcj02(double lat, double lon) {
    if (outOfChina(lat, lon)) {
      return null;
    }
    double dLat = transformLat(lon - 105.0, lat - 35.0);
    double dLon = transformLon(lon - 105.0, lat - 35.0);
    double radLat = lat / 180.0 * _pi;
    double magic = Math.sin(radLat);
    magic = 1 - _ee * magic * magic;
    double sqrtMagic = Math.sqrt(magic);
    dLat = (dLat * 180.0) / ((_a * (1 - _ee)) / (magic * sqrtMagic) * _pi);
    dLon = (dLon * 180.0) / (_a / sqrtMagic * Math.cos(radLat) * _pi);
    double mgLat = lat + dLat;
    double mgLon = lon + dLon;
    return  LatLng(mgLat, mgLon);
  }

  /**
   * * 火星坐标系 (GCJ-02) to 84 * * @param lon * @param lat * @return
   */
  static LatLng gcj_To_Gps84(double lat, double lon) {
    LatLng gps = transform(lat, lon);
    double lontitude = lon * 2 - gps.latitude;
    double latitude = lat * 2 - gps.longitude;
    return LatLng(latitude, lontitude);
  }

  /**
   * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 将 GCJ-02 坐标转换成 BD-09 坐标
   *
   * @param gg_lat
   * @param gg_lon
   */
  static LatLng gcj02_To_Bd09(double gg_lat, double gg_lon) {
    double x = gg_lon, y = gg_lat;
    double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * _pi);
    double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * _pi);
    double bd_lon = z * Math.cos(theta) + 0.0065;
    double bd_lat = z * Math.sin(theta) + 0.006;
    return LatLng(bd_lat, bd_lon);
  }

  /**
   * * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 * * 将 BD-09 坐标转换成GCJ-02 坐标 * * @param
   * bd_lat * @param bd_lon * @return
   */
  static LatLng bd09_To_Gcj02(double bd_lat, double bd_lon) {
    double x = bd_lon - 0.0065, y = bd_lat - 0.006;
    double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * _pi);
    double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * _pi);
    double gg_lon = z * Math.cos(theta);
    double gg_lat = z * Math.sin(theta);
    return LatLng(gg_lat, gg_lon);
  }

  /**
   * (BD-09)-->84
   * @param bd_lat
   * @param bd_lon
   * @return
   */
  static LatLng bd09_To_Gps84(double bd_lat, double bd_lon) {

    LatLng gcj02 = bd09_To_Gcj02(bd_lat, bd_lon);
    LatLng map84 = gcj_To_Gps84(gcj02.latitude,
        gcj02.longitude);
    return map84;

  }

  /**
   * is or not outOfChina
   * @param lat
   * @param lon
   * @return
   */
  static bool outOfChina(double lat, double lon) {
    if (lon < 72.004 || lon > 137.8347)
      return true;
    if (lat < 0.8293 || lat > 55.8271)
      return true;
    return false;
  }

  static LatLng transform(double lat, double lon) {
    if (outOfChina(lat, lon)) {
      return LatLng(lat, lon);
    }
    double dLat = transformLat(lon - 105.0, lat - 35.0);
    double dLon = transformLon(lon - 105.0, lat - 35.0);
    double radLat = lat / 180.0 * _pi;
    double magic = Math.sin(radLat);
    magic = 1 - _ee * magic * magic;
    double sqrtMagic = Math.sqrt(magic);
    dLat = (dLat * 180.0) / ((_a * (1 - _ee)) / (magic * sqrtMagic) * _pi);
    dLon = (dLon * 180.0) / (_a / sqrtMagic * Math.cos(radLat) * _pi);
    double mgLat = lat + dLat;
    double mgLon = lon + dLon;
    return LatLng(mgLat, mgLon);
  }

  static double transformLat(double x, double y) {
    double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y
        + 0.2 * Math.sqrt(x.abs());
    ret += (20.0 * Math.sin(6.0 * x * _pi) + 20.0 * Math.sin(2.0 * x * _pi)) * 2.0 / 3.0;
    ret += (20.0 * Math.sin(y * _pi) + 40.0 * Math.sin(y / 3.0 * _pi)) * 2.0 / 3.0;
    ret += (160.0 * Math.sin(y / 12.0 * _pi) + 320 * Math.sin(y * _pi / 30.0)) * 2.0 / 3.0;
    return ret;
  }


  static double transformLon(double x, double y) {
    double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1
        * Math.sqrt(x.abs());
    ret += (20.0 * Math.sin(6.0 * x * _pi) + 20.0 * Math.sin(2.0 * x * _pi)) * 2.0 / 3.0;
    ret += (20.0 * Math.sin(x * _pi) + 40.0 * Math.sin(x / 3.0 * _pi)) * 2.0 / 3.0;
    ret += (150.0 * Math.sin(x / 12.0 * _pi) + 300.0 * Math.sin(x / 30.0
        * _pi)) * 2.0 / 3.0;
    return ret;
  }
}